#include "JuegoServerImp.h"
#include "FabricaDeJugadores.h"
#include "Server.h"
#include "FabricaDeJugadores.h"
#include "EstadoDeEsperaDeJugadores.h"
#include "EstadoDePreparacionDePartida.h"
#include "EstadoDeRealizacionDePartida.h"
#include "EstadoDePartidaFinalizada.h"
#include "TurnoInvalidoException.h"
#include "TiradaInvalidaException.h"
#include "AtaqueInvalidoException.h"
#include "MovimientoDeEjercitosInvalidoException.h"
#include "NotEnoughPlayersException.h"
#include "PlayerIsNotOwnerException.h"
#include "JugadorExistenteException.h"
#include "ColocacionDeEjercitosInvalidaException.h"
#include "MensajeDeExcepcion.h"
#include "MensajeDeFinalizacion.h"
#include "MensajeChat.h"
#include <iostream>

using namespace std;

JuegoServerImp::JuegoServerImp(unsigned int cantidadDeJugadores, Mapa* mapa,TiradorDeDados* tiradorDeDados,
		Server* server, FabricaDeJugadores* fabricaDeJugadores) : Juego(cantidadDeJugadores,mapa)
{
	this->tiradorDeDados = tiradorDeDados;
	this->server = server;
	estadoDeEsperaDeJugadores = new EstadoDeEsperaDeJugadores(this);
	estadoDePreparacionDePartida = new EstadoDePreparacionDePartida(this);
	estadoDeRealizacionDePartida = new EstadoDeRealizacionDePartida(this);
	estadoDePartidaFinalizada = new EstadoDePartidaFinalizada(this);
	this->estadoDelJuego = estadoDeEsperaDeJugadores;
	this->fabricaDeJugadores = fabricaDeJugadores;
}

void JuegoServerImp::unirse(Jugador* jugador) {
	try { 
		this->estadoDelJuego->unirse(jugador);
	}catch (InvalidStateException e) {
		MensajeDeExcepcion mensaje(e);
		server->enviarMensaje(jugador, mensaje);
	}catch (JugadorExistenteException e) {
		MensajeDeExcepcion mensaje(e);
		server->enviarMensaje(jugador,mensaje);
	}
}

void JuegoServerImp::iniciar(Jugador* jugador) {
	if (this->getEstado() != this->getEstadoDeEsperaJugadores())
		throw InvalidStateException();
	if (jugadores.size() < 2)
		throw NotEnoughPlayersException();
	if (jugadores[0]->getColor() != jugador->getColor())
		throw PlayerIsNotOwnerException();
	((EstadoDeEsperaDeJugadores*)this->getEstado())->enviarDatosJugadores();
	this->setEstado(this->getEstadoDePreparacionDePartida());	
}

void JuegoServerImp::realizarAtaque(Ataque* ataque) {
	
	vector<Jugador*>* vec = this->getJugadores();
		
	string colorJugador = ataque->getJugadorAtacante()->getColor();
	string colorTurno = vec->at(turno)->getColor();
	
	if (colorJugador == colorTurno){
		try {
			this->estadoDelJuego->realizarAtaque(ataque);
		} catch (InvalidStateException e) {
			MensajeDeExcepcion mensaje(e);
			server->enviarMensaje(ataque->getJugadorAtacante(), mensaje);
		} catch (AtaqueInvalidoException e) {
			MensajeDeExcepcion mensaje(e);
			server->enviarMensaje(ataque->getJugadorAtacante(), mensaje);
		}
	}
	else {
		TurnoInvalidoException e;
		MensajeDeExcepcion mensaje(e);
		server->enviarMensaje(ataque->getJugadorAtacante(),mensaje);
	}
}

void JuegoServerImp::colocarEjercitos(Jugador* jugador, Territorio* territorio, unsigned int cantidadDeEjercitos) {
	
	vector<Jugador*>* vec = this->getJugadores();
	
	string colorJugador = jugador->getColor();
	string colorTurno = vec->at(turno)->getColor();
	
	if (colorJugador == colorTurno){
		try {
			this->estadoDelJuego->colocarEjercitos(jugador,territorio,cantidadDeEjercitos);
		} catch (InvalidStateException e) {
			MensajeDeExcepcion mensaje(e);
			server->enviarMensaje(jugador, mensaje);
		} catch (ColocacionDeEjercitosInvalidaException e) {
			MensajeDeExcepcion mensaje(e);
			server->enviarMensaje(jugador, mensaje);
		}
	}
	else {
		TurnoInvalidoException e;
		MensajeDeExcepcion mensaje(e);
		server->enviarMensaje(jugador,mensaje);
	}
}

void JuegoServerImp::moverEjercitos(Jugador* jugador, Territorio* origen, Territorio* destino, unsigned int cantidadDeEjercitos){
	
	vector<Jugador*>* vec = this->getJugadores();
		
	string colorJugador = jugador->getColor();
	string colorTurno = vec->at(turno)->getColor();
		
	if (colorJugador == colorTurno){
		try {
			this->estadoDelJuego->moverEjercitos(jugador,origen,destino,cantidadDeEjercitos);
		} catch (InvalidStateException e) {
			MensajeDeExcepcion mensaje(e);
			server->enviarMensaje(jugador, mensaje);
		} catch (MovimientoDeEjercitosInvalidoException e) {
			MensajeDeExcepcion mensaje(e);
			server->enviarMensaje(jugador, mensaje);
		}
	}
	else {
		TurnoInvalidoException e;
		MensajeDeExcepcion mensaje(e);
		server->enviarMensaje(jugador,mensaje);
	}
}

void JuegoServerImp::tirarDados(Jugador* jugador, unsigned int cantidadDeDados) {
	
	try {
		this->estadoDelJuego->tirarDados(jugador,cantidadDeDados);
	} catch (InvalidStateException e) {
		MensajeDeExcepcion mensaje(e);
		server->enviarMensaje(jugador,mensaje);
	} catch (TurnoInvalidoException e) {
		MensajeDeExcepcion mensaje(e);
		server->enviarMensaje(jugador,mensaje);
	} catch (TiradaInvalidaException e) {
		MensajeDeExcepcion mensaje(e);
		server->enviarMensaje(jugador,mensaje);
	}
}

void JuegoServerImp::pasar(Jugador* jugador) {
	
	vector<Jugador*>* vec = this->getJugadores();
		
	string colorJugador = jugador->getColor();
	string colorTurno = vec->at(turno)->getColor();
		
	if (colorJugador == colorTurno){
		try {
			this->estadoDelJuego->pasar(jugador);
		} catch (InvalidStateException e) {
			MensajeDeExcepcion mensaje(e);
			server->enviarMensaje(jugador,mensaje);
		}
	}
	else {
		TurnoInvalidoException e;
		MensajeDeExcepcion mensaje(e);
		server->enviarMensaje(jugador,mensaje);
	}
}

void JuegoServerImp::hablar(string nombreJugador, string mensaje) {
	for (int i = 0; i < jugadores.size(); i++)
		if (jugadores[i]->getNombre() != nombreJugador) {
			MensajeChat mensajeChat(nombreJugador,mensaje);
			server->enviarMensaje(jugadores[i], mensajeChat);
		}
}

TiradorDeDados* JuegoServerImp::getTiradorDeDados() {
	return tiradorDeDados;
}

void JuegoServerImp::setEstado(EstadoDelJuego* estado) {
	this->estadoDelJuego = estado;
	notifyObservers();
}

EstadoDelJuego* JuegoServerImp::getEstado() {
	return this->estadoDelJuego;
}

void JuegoServerImp::setTurno(int turno) {
	Juego::setTurno(turno);
	notifyObservers();
}

EstadoDelJuego* JuegoServerImp::getEstadoDeEsperaJugadores() {
	return estadoDeEsperaDeJugadores;
}

EstadoDelJuego* JuegoServerImp::getEstadoDePreparacionDePartida() {
	return estadoDePreparacionDePartida;
}

EstadoDelJuego* JuegoServerImp::getEstadoDeRealizacionDePartida() {
	return estadoDeRealizacionDePartida;
}

EstadoDelJuego* JuegoServerImp::getEstadoDePartidaFinalizada() {
	return estadoDePartidaFinalizada;
}

void JuegoServerImp::pasarAlSiguienteTurno() {
	if (turno == cantidadDeJugadores - 1)
		setTurno(0);
	else
		setTurno(turno + 1);
}

void JuegoServerImp::abandonar(Jugador* jugador) {
	if (this->getEstado()->toString() != this->getEstadoDePartidaFinalizada()->toString()) {
		MensajeDeFinalizacion mensaje("El jugador "+jugador->getColor()+" ha abandonado el juego");
		for (int i=0; i<this->jugadores.size(); i++) {
			Jugador* aux = jugadores[i];
			if (!(aux->getColor() == jugador->getColor()))
				server->enviarMensaje(aux, mensaje);
		}
		this->finalizar();
	}
}

Server* JuegoServerImp::getServer() {
	return server;
}

FabricaDeJugadores* JuegoServerImp::getFabricaDeJugadores() {
	return fabricaDeJugadores;
}

void JuegoServerImp::imprimirEstado() {
	cout<<"Estado del Juego"<<endl<<endl;
	cout<<"Cantidad de Jugadores : "<<getCantidadDeJugadores()<<endl;
	getMapa()->imprimirEstado();
}

void JuegoServerImp::finalizar() {
	if (!server->getTerminado())
		std::cout<<"El juego ha finalizado. Ingrese q para cerrar la aplicacion."<<endl;
	server->setTerminado();
	this->setEstado(this->getEstadoDePartidaFinalizada());
}

JuegoServerImp::~JuegoServerImp()
{
	delete estadoDeEsperaDeJugadores;
	delete estadoDePreparacionDePartida;
	delete estadoDeRealizacionDePartida;
	delete estadoDePartidaFinalizada;
}
